// This is the main worker.
// MainForm calls this for each locale to make it build & register itself
// We have to walk from the highest point (root) to the full locale and
// build the locale data piece by piece from the LDML.  We call LdmlData
// to load fields.
// Then we do clean up after the data's loaded and then register.
//
// Note that the specific locale data in CLDR is very sparse, so we have to 
// load the root.xml that applies and then build up the pieces as we need to.

using System;
using System.Collections.Generic;
using System.Text;
using System.Globalization;
using System.Reflection;

namespace customcldr
{
    class CldrLocale
    {
        static RegionInfo InvariantRegion = new RegionInfo("en-US");

        String strFilePath;
        public String strLocaleName;        // full name, ie: en-US
        public String strLanguage = null;   // language, ie en
        public String strSublanguage = null;// BUG: Not done - sub language, ie: cmn in zh-cmn.  CLDR doesn't have this yet?
        public String strScript = null;     // script, ie: Latn
        public String strRegion = null;     // region, ie: US in en-US
        public String strVariant = null;    // variant
        String strLocalizedDisplayName;
        String strEnglishDisplayName;
        String strNativeDisplayName;
        CultureAndRegionInfoBuilder carib = null;
        CultureInfo culture = null;
        RegionInfo region = null;
        LdmlData ldmlData = null;
        int dashes = -1;

        public bool IsSystemLocale = false;
        public bool IsInstalledLocale = false;
        public bool IsNeutralLocale = false;
        public bool IsRoot = false;

        // This constructs our object from the full path to the xml and file name
        internal CldrLocale(String strFullPath, String strFileName)
        {
            this.strFilePath = strFullPath;
            this.strLocaleName = strFileName.Replace(".xml", "");
            this.strLocaleName = this.strLocaleName.Replace("_", "-");

            this.IsRoot = (this.strLocaleName == "root");

            this.ParseName();

            FindBaseCultureAndRegion();
        }

        // Find our base culture and region (as built-in as possible)
        internal void FindBaseCultureAndRegion()
        {
            this.culture = null;
            this.region = null;

            // See if we happen to be an available locale
            this.IsNeutralLocale = (strRegion == null || strRegion == "");

            try
            {
                this.culture = CultureInfo.GetCultureInfo(strLocaleName);
                this.IsInstalledLocale = true;
                this.IsSystemLocale =
                    ((culture.CultureTypes & CultureTypes.UserCustomCulture) == 0);
                this.IsNeutralLocale =
                    ((culture.CultureTypes & CultureTypes.NeutralCultures) == CultureTypes.NeutralCultures);
                this.region = new RegionInfo(strLocaleName);
            }
            catch (ArgumentException)
            {
                // Ignore errors, we'll fill this in later when registering.
            }

            // If the region is null we may have a built-in region to use
            if (this.region == null && 
                (strRegion != null && strRegion != ""))
            {
                try
                {
                    this.region = new RegionInfo(this.strRegion);
                }
                catch (ArgumentException)
                {
                }
            }

            // specific locales now have both null regions & cultures
            // neutral locales may have a null region but a neutral culture
            String strParent = this.strLocaleName;
            while (this.culture == null)
            {
                try
                {
                    int index = strParent.LastIndexOf('-');
                    if (index > 0)
                        strParent = strParent.Substring(0, index);
                    else
                        strParent = "";
                    this.culture = new CultureInfo(strParent);
                }
                catch (ArgumentException)
                {
                }
            }

            strParent = this.strLocaleName;
            while (this.region == null)
            {
                try
                {
                    int index = strParent.LastIndexOf('-');
                    if (index > 0)
                        strParent = strParent.Substring(0, index);
                    else
                        strParent = "en-US";    // Fall back to en-US
                    this.region = new RegionInfo(strParent);
                }
                catch (ArgumentException)
                {
                }
            }

            // we should now have at least invariant locale/region
        }

        // Get an LDML object so we can talk to our LDML data
        public LdmlData LdmlData
        {
            get
            {
                if (ldmlData == null)
                {
                    ldmlData = new LdmlData(this.strFilePath);
                }
                return ldmlData;
            }
        }

        // This builds and registers our culture
        //
        // 1 we make a CultureANdRegionInfoBuilder for our new locale.
        // 2 We initialize that CulstureAndRegionInfoBuilder
        // 3 We load the root data for our locale.
        // 4 We go through each part of our name to build up the locale.  (ie: en then en-US)
        // 5 
        internal void Register()
        {
            Console.WriteLine("Registering " + this.ToString());

            // Get our base .Net locale/region as much as possible
            // We do this again because we may have built a neutral since
            // we created the original list in MainForm.
            FindBaseCultureAndRegion();

            // Start at root & build ourselves up locale by locale
            CultureAndRegionModifiers mod = CultureAndRegionModifiers.None;
            if (this.IsSystemLocale)
            {
                mod = CultureAndRegionModifiers.Replacement;
            }
            if (this.IsNeutralLocale)
            {
                mod |= CultureAndRegionModifiers.Neutral;
            }

            carib = new CultureAndRegionInfoBuilder(this.strLocaleName, mod);
            
            // Load the defaults
            InitCarib();
            LoadDataFrom("root");

            // Load each additional part since the CLDR builds on the earlier parts.
            // BUG: technically we're probably supposed to look up that in the <identity>
            // BUG: but that is hard.
            int i = 0;
            while (i < this.strLocaleName.Length)
            {
                i = this.strLocaleName.IndexOf('-', i + 1);
                if (i < 0) i = this.strLocaleName.Length;
                LoadDataFrom(this.strLocaleName.Substring(0, i));
            }

            // Some properties are better by themselves after
            // loading the rest of the data
            FinishCarib();

            // Now we have all our data, so register it.
            RegisterCarib();
        }

        // 
        // locale names look like this:  See RFC 4646. http://ietf.org/rfc/rfc4646.txt
        //   ll(l)-{uuu}-{ssss}-{rr}{nnn}-{vvvvv}
        //
        // ll(l) is a 2 or 3 character major language, ie: zh, tlh
        // {uuu} is an optional sublanguage, eg: cmn in zh-cmn
        // {ssss} is an optional script, eg: Hant in zh-Hant-cn
        // {rr}{nnn} is an optional region, either 2 letters or 3 numbers, eg: US in en-US and 029 in en-029.
        // {vvvvv} is an optional variant.  
        void ParseName()
        {
            String strTemp = this.strLocaleName;
            string strPart;
            
            // locale names look like:
            // xx, xxx, xx-xx, xxx-xx, xx-xxxx, xxx-xxxx, xx-xxxxx, xxx-xxxxx, xx-xxxx-xx, xxx-xxxx-xx, xx-xxxx-xx-xxxxx, xxx-xxxx-xx-xxxxx
            int i = strTemp.IndexOf('-');

            // language is always 1st, should be 2 or 3 letters.
            if (i > 0)
            {
                this.strLanguage = strTemp.Substring(0, i);
                strTemp = strTemp.Substring(i+1);
            }
            else   
            {
                this.strLanguage = strTemp;
                strTemp = "";
            }
            
            // get next part
            i = strTemp.IndexOf('-');
            if (i > 0)
            {
                strPart = strTemp.Substring(0, i);
                strTemp = strTemp.Substring(i+1);
            }
            else
            {
                strPart = strTemp;
                strTemp = "";
            }

            // sublang might be next, it has 3 letters
            if (strPart.Length == 3 && char.IsLetter(strPart[0]))
            {
                // was a sublang
                this.strSublanguage = strPart;

                // get next part
                i = strTemp.IndexOf('-');
                if (i > 0)
                {
                    strPart = strTemp.Substring(0, i);
                    strTemp = strTemp.Substring(i + 1);
                }
                else
                {
                    strPart = strTemp;
                    strTemp = "";
                }
            }

            // Next might be script, which is 4 letters
            if (strPart.Length == 4 && char.IsLetter(strPart[0]))
            {
                // was a script
                this.strScript = strPart;

                // get next part
                i = strTemp.IndexOf('-');
                if (i > 0)
                {
                    strPart = strTemp.Substring(0, i);
                    strTemp = strTemp.Substring(i + 1);
                }
                else
                {
                    strPart = strTemp;
                    strTemp = "";
                }
            }

            // Next might be a region, which is 2 letters or 3 numbers
            if ((strPart.Length == 2 && char.IsLetter(strPart[0])) ||
                (strPart.Length == 3 && char.IsDigit(strPart[0])))
            {
                // was a Region
                this.strRegion = strPart;

                // get next part
                i = strTemp.IndexOf('-');
                if (i > 0)
                {
                    strPart = strTemp.Substring(0, i);
                    strTemp = strTemp.Substring(i + 1);
                }
                else
                {
                    strPart = strTemp;
                    strTemp = "";
                }
            }

            // rest is variant
            this.strVariant = strPart;
        }

        internal void InitCarib()
        {
            // Load the default values as much as we can.
            // culture should be at least an invariant
            carib.LoadDataFromCultureInfo(culture);

            if (this.IsNeutralLocale == false)
            {
                // region should be at least invariant
                carib.LoadDataFromRegionInfo(region);
            }
        }

        // Look up a locale by name and load its data from ldml
        internal void LoadDataFrom(string strLanguage)
        {
            Console.WriteLine("Loading " + strLanguage);
            CldrLocale loadFrom = CldrLocaleList.LocaleList.GetLocale(strLanguage);

            LoadDataFrom(loadFrom.LdmlData);
        }

        // Load our data from LDML, this overwrites anything previously loaded.
        internal void LoadDataFrom(LdmlData data)
        {
            if (!IsNeutralLocale)
            {
                // BUG: This (the worker) is incomplete
                DateTimeFormatInfo greg = data.UpdateGregorian(carib.GregorianDateTimeFormat);
                carib.GregorianDateTimeFormat = greg;

                // BUG: This (the worker) is incomplete
                NumberFormatInfo nfi = data.UpdateNumberFormats(carib.NumberFormat);
                carib.NumberFormat = nfi;

                // CLDR might not have all of these as expected.  Root has ALL calendars
                // its unclear what the children have.
                Calendar[] cals = data.UpdateCalendars(carib.AvailableCalendars);
                if (cals != null)
                    carib.AvailableCalendars = cals;
            }

            // TextInfo.  Don't really have base, but can do list separator
            // BUG: This (the worker) is incomplete
            if (this.IsSystemLocale == false)
            {
                TextInfo ti = data.UpdateTextInfo(carib.TextInfo);
                carib.TextInfo = ti;
            }

            // BUG: carib.IsMetric
            // Unable to figure this out in the LDML
            if (!IsNeutralLocale)
            {
                if (this.strRegion == "US") carib.IsMetric = false;
                else carib.IsMetric = true;
            }

            // currency symbol
            if (!IsNeutralLocale)
            {
                if (!string.IsNullOrEmpty(data.IsoCurrencySymbol))
                    carib.ISOCurrencySymbol = data.IsoCurrencySymbol;
            }
        }

        internal void FinishCarib()
        {
            // Need to set calendar names, which is a bit annoying
            String[] calendarNames = this.NativeCalendarNames();
            SetCaribPrivateField("m_calendarNames", calendarNames);

            // Clean up the names, 1st region names
            if (!IsNeutralLocale)
            {
                if (!string.IsNullOrEmpty(this.EnglishRegionName))
                    carib.RegionEnglishName = this.EnglishRegionName;
                if (!string.IsNullOrEmpty(this.NativeRegionName))
                    carib.RegionNativeName = this.NativeRegionName;
                if (!string.IsNullOrEmpty(this.strRegion) && carib.RegionName != this.strRegion)
                    Console.WriteLine("Unexpected difference in region names:\ncarib.RegionName {0}\nthis.strRegion {1}",
                        carib.RegionName, this.strRegion);
            }

            // BUG: Language has to be done by reflection,
            // see http://msdn2.microsoft.com/en-us/library/ms404375.aspx
            // and http://blogs.msdn.com/shawnste/archive/2006/08/07/691257.aspx
            if (!string.IsNullOrEmpty(this.EnglishLanguageName))
                SetCaribPrivateField("m_englishLanguage", this.EnglishLanguageName);
            if (!string.IsNullOrEmpty(this.NativeLanguageName))
                SetCaribPrivateField("m_nativeLanguage", this.NativeLanguageName);
            
            if (!string.IsNullOrEmpty(this.EnglishDisplayName))
                carib.CultureEnglishName = this.EnglishDisplayName;
            if (!string.IsNullOrEmpty(this.NativeDisplayName))
                carib.CultureNativeName = this.NativeDisplayName;

            if (!IsNeutralLocale)
            {
                if (!string.IsNullOrEmpty(this.EnglishCurrencyName))
                    carib.CurrencyEnglishName = this.EnglishCurrencyName;
                if (!string.IsNullOrEmpty(this.NativeCurrencyName))
                    carib.CurrencyNativeName = this.NativeCurrencyName;
            }

            carib.TwoLetterISOLanguageName = this.strLanguage;
            // These aren't strictly correct, but this isthe best we can do.
            if (string.IsNullOrEmpty(this.strSublanguage))
            {
                carib.ThreeLetterISOLanguageName = this.strLanguage;
                if (this.IsSystemLocale == false)
                    carib.ThreeLetterWindowsLanguageName = this.strLanguage.ToUpper();
            }
            else
            {
                carib.ThreeLetterISOLanguageName = this.strSublanguage;
                if (this.IsSystemLocale == false)
                    carib.ThreeLetterWindowsLanguageName = this.strSublanguage.ToUpper();
            }

            if (!IsNeutralLocale)
            {
                if (!string.IsNullOrEmpty(strRegion))
                {
                    carib.TwoLetterISORegionName = this.strRegion;
                    // These aren't strictly correct, but this is the best we can do.
                    carib.ThreeLetterISORegionName = this.strRegion;
                    if (this.IsSystemLocale == false)
                        carib.ThreeLetterWindowsRegionName = this.strRegion;
                }
            }

            // Parent
            CultureInfo parent = null;
            string strParent = strLocaleName;
            while (parent == null)
            {
                try
                {
                    int index = strParent.LastIndexOf('-');
                    if (index > 0)
                        strParent = strParent.Substring(0, index);
                    else
                        strParent = "";
                    parent = new CultureInfo(strParent);
                }
                catch (ArgumentException)
                {
                }
            }
            carib.Parent = parent;

            // Set the scripts property using the Vista GetStringScripts() API
            // Note that if CultureNativeName is wrong, then we'll get m_scripts wrong.
            String scripts = VistaNative.GetStringScripts(carib.CultureNativeName);
            SetCaribPrivateField("m_scripts", scripts);

            // BUG: need to build comparinfo-textinfo
            // CompareInfo/TextInfo can probably be the same, but it'll be hard
            // to figure out.  Maybe if we happen to have the language we could use
            // that, but that won't help new languages -- use English/Invariant?
            // For now just leave them as default (which is either the system, language
            // or invariant that was created when we first loaded culture data.
            //carib.CompareInfo 

            // Console fallback culture - no good guess, just use en-US.
            // BUG: Better guess?
            carib.ConsoleFallbackUICulture = new CultureInfo("en-US");

            // BUG: need to get a  geoid, these will be default
            //carib.GeoId - can't figure out from LDML
            //carib.KeyboardLayoutId - can't figure out from LDML

            // BUG: need to calculate isrighttoleft, not sure this is complete
            carib.IsRightToLeft = ((scripts.IndexOf("Hebr") >=0) ||
                                   (scripts.IndexOf("Arab") >=0));
        }

        // BUG: Language has to be done by reflection,
        // see http://msdn2.microsoft.com/en-us/library/ms404375.aspx
        // and http://blogs.msdn.com/shawnste/archive/2006/08/07/691257.aspx
        static Type tCarib = null;
        private void SetCaribPrivateField(string strPropertyName, Object oValue)
        {
            if (tCarib == null) tCarib = carib.GetType();
            FieldInfo field = tCarib.GetField(
                strPropertyName, BindingFlags.Instance | BindingFlags.NonPublic);
            field.SetValue(carib, oValue);
        }

        internal void RegisterCarib()
        {
            try
            {
                CultureAndRegionInfoBuilder.Unregister(this.strLocaleName);
            }
            catch
            {
            }

            carib.Register();
        }
        
        // Try to make a localized display name, if we have an exact system
        // match we can use that, otherwise we have to build it from the LDML
        // This is ONLY used in the list, its not stored in the carib for some reason.
        String LocalizedDisplayName
        {
            get
            {
                if (this.strLocalizedDisplayName == null)
                {
                    if (culture != null && culture.Name == this.strLocaleName)
                    {
                        this.strLocalizedDisplayName = culture.DisplayName;
                    }
                    else
                    {
                        // see if we happen to have Microsoft LDML
                        // (commented out because this makes everything really, really slow)
                        if (CldrLocaleList.LocaleList.LocalizedLanguageName == "en")
                        {
                            // They had an English UI choice
                       //     this.strLocalizedDisplayName = 
                         //       this.LdmlData.GetMicrosoftEnglishDisplayName();
                        }
                        else if (CldrLocaleList.LocaleList.LocalizedLanguageName == this.strLanguage)
                        {
                            // They had some other name that matched our locale, so use native name
                      //      this.strLocalizedDisplayName = 
                        //        this.LdmlData.GetMicrosoftNativeDisplayName();
                        }

                        // If it is still empty, then try harder.
                        if (string.IsNullOrEmpty(this.strLocalizedDisplayName))
                        {
                            // Want language, variant (script, region)
                            this.strLocalizedDisplayName = this.LocalizedLanguageName;
                            if (!string.IsNullOrEmpty(strVariant))
                            {
                                this.strLocalizedDisplayName += ", " + this.LocalizedVariantName;
                            }
                            if (!string.IsNullOrEmpty(this.strRegion) ||
                                !string.IsNullOrEmpty(this.strScript))
                            {
                                this.strLocalizedDisplayName += " (";
                                if (!string.IsNullOrEmpty(this.strScript))
                                {
                                    this.strLocalizedDisplayName += this.LocalizedScriptName;
                                    if (!string.IsNullOrEmpty(this.strRegion))
                                        this.strLocalizedDisplayName += ", ";
                                }
                                if (!string.IsNullOrEmpty(this.strRegion))
                                    this.strLocalizedDisplayName += this.LocalizedRegionName;
                                this.strLocalizedDisplayName += ")";
                            }
                        }
                    }
                }
                return this.strLocalizedDisplayName;
            }
        }

        // We ONLY use this for display
        string strLocalizedLanguageName = null;
        String LocalizedLanguageName
        {
            get
            {
                if (strLocalizedLanguageName == null)
                {
                    strLocalizedLanguageName =
                        CldrLocaleList.LocaleList.Localized.LdmlData.GetLanguageDisplayName(this.strLanguage);
                }
                return strLocalizedLanguageName;
            }
        }

        // We ONLY use this for display
        string strLocalizedRegionName = null;
        String LocalizedRegionName
        {
            get
            {
                if (strLocalizedRegionName == null)
                {
                    strLocalizedRegionName =
                        CldrLocaleList.LocaleList.Localized.LdmlData.GetRegionDisplayName(this.strRegion);
                }
                return strLocalizedRegionName;
            }
        }

        // We ONLY use this for display
        string strLocalizedScriptName = null;
        String LocalizedScriptName
        {
            get
            {
                if (strLocalizedScriptName == null)
                {
                    strLocalizedScriptName =
                        CldrLocaleList.LocaleList.Localized.LdmlData.GetScriptDisplayName(this.strScript);
                }
                return strLocalizedScriptName;
            }
        }

        // We ONLY use this for display
        string strLocalizedVariantName = null;
        String LocalizedVariantName
        {
            get
            {
                if (strLocalizedVariantName == null)
                {
                    strLocalizedVariantName =
                        CldrLocaleList.LocaleList.Localized.LdmlData.GetVariantDisplayName(this.strVariant);
                }
                return strLocalizedVariantName;
            }
        }

        // This makes a name for our list on the main form.
        // We want it to look like en-us     English (United States)
        // in whatever the user's display language is.
        String toStringName = null;
        public override String ToString()
        {
            if (toStringName == null)
            {
                toStringName = this.strLocaleName;
                if (toStringName.Length < 8) this.toStringName += "\t";

                this.toStringName += "\t" + this.LocalizedDisplayName;
            }

            return this.toStringName;
        }

        // Try to create an english display name
        String EnglishDisplayName
        {
            get
            {
                if (this.strEnglishDisplayName == null)
                {
                    // Don't have a name yet, get it from the LDML
                    // Note that a Microsoft LDML name would be most complete
                    // so try that first.
                    this.strEnglishDisplayName = 
                        this.LdmlData.GetMicrosoftEnglishDisplayName();

                    // If its still empty we have to build it from the CLDR ldml
                    if (string.IsNullOrEmpty(this.strEnglishDisplayName))
                    {
                        // Want language, variant (script, region)
                        this.strEnglishDisplayName = this.EnglishLanguageName;
                        if (!string.IsNullOrEmpty(strVariant))
                        {
                            this.strEnglishDisplayName += ", " + this.EnglishVariantName;
                        }
                        if (!string.IsNullOrEmpty(this.strRegion) ||
                            !string.IsNullOrEmpty(this.strScript))
                        {
                            this.strEnglishDisplayName += " (";
                            if (!string.IsNullOrEmpty(this.strScript))
                            {
                                this.strEnglishDisplayName += this.EnglishScriptName;
                                if (!string.IsNullOrEmpty(this.strRegion))
                                    this.strEnglishDisplayName += ", ";
                            }
                            if (!string.IsNullOrEmpty(this.strRegion))
                                this.strEnglishDisplayName += this.EnglishRegionName;
                            this.strEnglishDisplayName += ")";
                        }
                    }
                }
                return this.strEnglishDisplayName;
            }
        }

        // Try to create an english language name
        string strEnglishLanguageName = null;
        String EnglishLanguageName
        {
            get
            {
                if (strEnglishLanguageName == null)
                {
                    if (!string.IsNullOrEmpty(strSublanguage))
                    {
                        strEnglishLanguageName =
                            CldrLocaleList.English.LdmlData.GetLanguageDisplayName(this.strSublanguage);
                    }
                    if (string.IsNullOrEmpty(strEnglishLanguageName))
                    {
                        strEnglishLanguageName =
                            CldrLocaleList.English.LdmlData.GetLanguageDisplayName(this.strLanguage);
                    }
                }
                return strEnglishLanguageName;
            }
        }

        // Try to create an english region name
        string strEnglishRegionName = null;
        String EnglishRegionName
        {
            get
            {
                if (strEnglishRegionName == null)
                {
                    strEnglishRegionName =
                        CldrLocaleList.English.LdmlData.GetRegionDisplayName(this.strRegion);
                }
                return strEnglishRegionName;
            }
        }

        // Make an english script name
        string strEnglishScriptName = null;
        String EnglishScriptName
        {
            get
            {
                if (strEnglishScriptName == null)
                {
                    strEnglishScriptName =
                        CldrLocaleList.English.LdmlData.GetScriptDisplayName(this.strScript);
                }
                return strEnglishScriptName;
            }
        }

        // Get an english variant name
        string strEnglishVariantName = null;
        String EnglishVariantName
        {
            get
            {
                if (strEnglishVariantName == null)
                {
                    strEnglishVariantName =
                        CldrLocaleList.English.LdmlData.GetVariantDisplayName(this.strVariant);
                }
                return strEnglishVariantName;
            }
        }

        string strEnglishCurrencyName = null;
        String EnglishCurrencyName
        {
            get
            {
                if (strEnglishCurrencyName == null)
                {
                    strEnglishCurrencyName =
                        CldrLocaleList.English.LdmlData.GetCurrencyDisplayName(carib.ISOCurrencySymbol);
                }
                return strEnglishCurrencyName;
            }
        }

        String NativeDisplayName
        {
            get
            {
                if (this.strNativeDisplayName == null)
                {
                    // Don't have a name yet, get it from the LDML
                    // Note that a Microsoft LDML name would be most complete
                    // so try that first.
                    this.strNativeDisplayName =
                        this.LdmlData.GetMicrosoftNativeDisplayName();

                    // If its still empty we have to build it from the CLDR ldml
                    if (string.IsNullOrEmpty(this.strNativeDisplayName))
                    {
                        // Want language, variant (script, region)
                        this.strNativeDisplayName = this.NativeLanguageName;
                        if (!string.IsNullOrEmpty(strVariant))
                        {
                            this.strNativeDisplayName += ", " + this.NativeVariantName;
                        }
                        if (!string.IsNullOrEmpty(this.strRegion) ||
                            !string.IsNullOrEmpty(this.strScript))
                        {
                            this.strNativeDisplayName += " (";
                            if (!string.IsNullOrEmpty(this.strScript))
                            {
                                this.strNativeDisplayName += this.NativeScriptName;
                                if (!string.IsNullOrEmpty(this.strRegion))
                                    this.strNativeDisplayName += ", ";
                            }
                            if (!string.IsNullOrEmpty(this.strRegion))
                                this.strNativeDisplayName += this.NativeRegionName;
                            this.strNativeDisplayName += ")";
                        }
                    }
                }
                return this.strNativeDisplayName;
            }
        }

        string strNativeLanguageName = null;
        String NativeLanguageName
        {
            get
            {
                if (strNativeLanguageName == null)
                {
                    CldrLocale temp = this;
                    if (!string.IsNullOrEmpty(this.strSublanguage))
                    {
                        while (string.IsNullOrEmpty(strNativeLanguageName) && temp != null)
                        {
                            strNativeLanguageName =
                                temp.LdmlData.GetLanguageDisplayName(this.strSublanguage);

                            temp = temp.Parent;
                        }
                    }
                    
                    temp = this;
                    while (string.IsNullOrEmpty(strNativeLanguageName) && temp != null)
                    {
                        strNativeLanguageName =
                            temp.LdmlData.GetLanguageDisplayName(this.strLanguage);

                        temp = temp.Parent;
                    }

                    if (strNativeLanguageName == null)
                    {
                        strNativeLanguageName = EnglishLanguageName;
                    }
                }
                return strNativeLanguageName;
            }
        }

        string strNativeRegionName = null;
        String NativeRegionName
        {
            get
            {
                if (strNativeRegionName == null)
                {
                    CldrLocale temp = this;

                    while ((strNativeRegionName == null || strNativeRegionName == String.Empty) && temp != null)
                    {
                        strNativeRegionName =
                            temp.LdmlData.GetRegionDisplayName(this.strRegion);

                        temp = temp.Parent;
                    }

                    if (strNativeRegionName == null)
                    {
                        strNativeRegionName = EnglishRegionName;
                    }
                }
                return strNativeRegionName;
            }
        }

        string strNativeScriptName = null;
        String NativeScriptName
        {
            get
            {
                if (strNativeScriptName == null)
                {
                    CldrLocale temp = this;

                    while ((strNativeScriptName == null || strNativeScriptName == String.Empty) && temp != null)
                    {
                        strNativeScriptName =
                            temp.LdmlData.GetScriptDisplayName(this.strScript);

                        temp = temp.Parent;
                    }

                    if (strNativeScriptName == null)
                    {
                        strNativeScriptName = EnglishScriptName;
                    }
                }
                return strNativeScriptName;
            }
        }

        string strNativeVariantName = null;
        String NativeVariantName
        {
            get
            {
                if (strNativeVariantName == null)
                {
                    CldrLocale temp = this;

                    while ((strNativeVariantName == null || strNativeVariantName == String.Empty) && temp != null)
                    {
                        strNativeVariantName =
                            temp.LdmlData.GetVariantDisplayName(this.strVariant);

                        temp = temp.Parent;
                    }

                    if (strNativeVariantName == null)
                    {
                        strNativeVariantName = EnglishVariantName;
                    }
                }
                return strNativeVariantName;
            }
        }

        string strNativeCurrencyName = null;
        String NativeCurrencyName
        {
            get
            {
                if (strNativeCurrencyName == null)
                {
                    CldrLocale temp = this;

                    while ((strNativeCurrencyName == null || strNativeCurrencyName == String.Empty) && temp != null)
                    {
                        strNativeCurrencyName =
                            temp.LdmlData.GetCurrencyDisplayName(carib.ISOCurrencySymbol);

                        temp = temp.Parent;
                    }

                    if (strNativeCurrencyName == null)
                    {
                        strNativeCurrencyName = EnglishCurrencyName;
                    }
                }
                return strNativeCurrencyName;
            }
        }

        string strParent = null;
        CldrLocale parent = null;
        CldrLocale Parent
        {
            get
            {
                if (parent == null)
                {
                    int i = this.strLocaleName.LastIndexOf("-");
                    if (i == -1)
                    {
                        if (this.strLocaleName != "root") strParent = "root";
                        else strParent = String.Empty;
                    }
                    else strParent = this.strLocaleName.Substring(0, i);

                    if (strParent == String.Empty)
                        return null;

                    parent = CldrLocaleList.LocaleList.GetLocale(strParent);
                }
                return parent;
            }
        }

        internal int Dashes()
        {
            if (dashes < 0)
            {
                dashes = 0;
                int i = 0;
                while ((i = strLocaleName.IndexOf('-', i+1)) > 0)
                {
                    dashes++;
                }
            }

            return dashes;
        }

        internal String[] NativeCalendarNames()
        {
            // Make room for them. 0 based array of 1 based calendars
            String[] names = new String[23];

            for (int i = 1; i <= 23; i++)
            {
                CldrLocale parent = this;
                while (String.IsNullOrEmpty(names[i-1]) && parent != null)
                {
                    names[i-1] = parent.LdmlData.GetCalendarName(i);
                    parent = parent.Parent;
                }
            }

            return names;
        }
    }
}
